/**
  ETFRoot project, Anyang Normal University && IMP-CAS
  \class ETFPDCR
  \brief for DCs around the target. PDCL is Proton DC the Left, constructed in
  Japan and reused by BUAA.
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-31
  \date 2021-10-31 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-31   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <cstring>
#include <TClonesArray.h>
#include "ETFPDCR.h"
#include "ETFDCHit.h"
#include "ETFMath.h"
#include "ETFMsg.h"
#include "ETFParaManager.h"
#include "ETFYaml.h"

ClassImp(ETFPDCR);

static const double DEGREE = ETFMath::DEGREE();
ETFPDCR::ETFPDCR(const char *name) : ETFPDC(name){
  memset(type, 0, sizeof(type)); // may not be necessary
  const YAML::Node &chIdConfig = (*ETFParaManager::Instance()->GetChIdPara())[name];
  for(const auto &chid : chIdConfig){
    FillXYChMap(chid.as<int>());
    type[0]++; // 0: X; 1: Y
  } // end for over cables
} // end ctor

ETFPDCR::~ETFPDCR(){}

// fill the channel map for X or Y wires
// XY, X1-X2, senseWireId
void ETFPDCR::FillXYChMap(int chId0){
  if(chId0 < 0) return;
  for(int i = 0; i < 2; i++) for(int j = 0; j < NL; j++)
    //      chanel id                    X-Y     X1-2  wireId: 0-7
    SetChIdMap(chId0+14+i-2*j, fDetId+(type[0]<<8)+(i<<9)+(j<<10));
} // end member function FillCableChMap

void ETFPDCR::AddHit(const ETFHPTDCChannel *ch, int wireId, DCType typeDC){
  int x12 = wireId / NL, id = wireId % NL;
  short xy = short(typeDC);
  char cc; // = 'x' or 'y' according to xy
  ETFDCHit *hit =
    dynamic_cast<ETFDCHit *>(fHits[xy][x12]->ConstructedAt(fHits[xy][x12]->GetEntries()));
  hit->Initialize();
  hit->SetDataChannel(ch);
  hit->SetLayerId(GetDCId()*2+x12); // 0-1-2-3-4-5: DC0X1-X2--DC1X1-X2--DC2X1-X2
  hit->SetWireId(id);
  hit->SetDelay(fDelay);
  // set position in local frame
  static const double x0 = -65.; // 15.-10*NL, NL = 8 is NofWire per layer
  if(0 == xy){ // X
    cc = 'x';
    hit->SetX(x0+20.*id-10.*x12);
    hit->SetY(0.);
    hit->SetZ(10.*x12);
  } // end if
  if(1 == xy){ // Y
    cc = 'y';
    hit->SetX(0.);
    hit->SetY(x0+20.*id-10.*x12);
    hit->SetZ(10.*x12+20.);
  } // end if
  char name[128]; sprintf(name, "%s_%c%d_id%d", GetName(), cc, x12, id);
  hit->SetName(name);

  TransformToLabRef(hit);
  SetHitProjection(hit, typeDC); // set projection of the wire center position to the wire's normal plane
} // end member function AddHit

// r = r(t); drift distance - drift time relation
double ETFPDCR::SpaceTimeRelation(double t){
  // note that the following parameterization is for HV = 1030V
  // usually STR at other HVs are so different as worth special treatment
  // be it a garfield simulation, or user-refined tuning based on experiment data analysis
  static constexpr int POLN = 8;
  static const double p[POLN] = {0.504161, 0.0306897, 0.000301748, -3.61528e-06,
    1.72443e-08, -4.36404e-11, 5.75065e-14, -3.1056e-17};
  double r = 0.;
  for(int i = POLN; i--;) r += p[i]*pow(t, i);
  if(r < 0. || t < -10.) r = 0.;
  if(r > 10. || t > 550.) r = 10.;

  return r;
} // end member function SpaceTimeRelation
